/*  

Cafechess Library: Cover basic chess programming needs, like GUI, Engine integration, 
FEN and PGN parsing.

                 \\|//
                 (o o)
--------------ooO-(_)-Ooo----------------------------------
Copyright (C) 2009  By Gregory A. Prentice Snoqualmie, WA
                    www.cafechess.org
                    cafechess@comcast.net
                      Oooo
--------------oooO----(  )---------------------------------
              (  )    (_/
               \_)

Microsoft Public License (Ms-PL)
               
Revisions:

Author        Date    Description:

*/
using System;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

using Cafechess.Imaging;
using Cafechess.Imaging.Draw;
using Cafechess.General.Handle;
namespace Cafechess.Chess.Controls
{
	/// <summary>
	/// Provides the Top and Mid DrawingLayers and are responsible for producing
	/// arrows, circles, squares and such on our image.
	/// </summary>
  public class DrawingLayer: Layer, IMouseEvents
  {
    Keys coKey;
    int coPenWidth;
    public Keys CurrentKey
    {
      set{ coKey = value; }
      get{ return coKey; }
    }
    Color coCurrentColor;
    public Color PenColor
    {
      get{ return coCurrentColor;}
      set{ coCurrentColor = value;}
    }
    public int PenWidth
    {
      get{return coPenWidth;}
      set{coPenWidth = value;}
    }
    public GraphicSettings BalloonSettings
    {
      get{ return coBalloonSettings;}
      set{ coBalloonSettings = value;}

    }
    GraphicSettings coBalloonSettings;
    /// <summary>
    /// Construct our surface object that will manage the physical drawing bitmap
    /// and the order in which our layers are applied to the image.
    /// </summary>
    /// <param name="rectangle"></param>
    public DrawingLayer(Rectangle rectangle, Color background) : base(rectangle,background)
    {
      // Default nothing tools
      coKey = Keys.NumPad0;
      PenColor = Color.DarkBlue;
      PenWidth = 4;
      coBalloonSettings  = new GraphicSettings();
      coBalloonSettings.BackColor = Color.LightYellow;
      coBalloonSettings.BorderColor = Color.Red;
      coBalloonSettings.X = 25;
      coBalloonSettings.Y = 25;
      coBalloonSettings.PenWidth = 1;
      coBalloonSettings.Radius = 5;     
      coBalloonSettings.Height = 50;
      coBalloonSettings.Width = 100;
      coBalloonSettings.TextColor = Color.DarkGreen;
      coBalloonSettings.ApplyBorder = true; 
      coBalloonSettings.Orientation = 6;

    }

    /// <summary>
    /// Retrieves a string representing the drawable objects currently being displayed.
    /// </summary>
    /// <returns></returns>
    override public string ToString()
    {
      StringBuilder builder = new StringBuilder();
      bool delimit = false;
      foreach(IDrawable idraw in this)
      {
        DrawOnMouseEvents dm = idraw as DrawOnMouseEvents;
        if(dm != null )
        {
          if(delimit)
            builder.Append("/");
          else
            delimit = true;
          builder.Append(dm.Name);
          builder.Append(":");
          builder.Append(ColorTranslator.ToHtml(dm.Pen.Color));
          builder.Append(":");
          builder.Append(dm.Pen.Width);
        }
      }
      return builder.ToString();
    }
    
    /// <summary>
    /// Rebuild our drawing layer objects.  The string consists of
    /// a delimited string of IDrawable objects by the "/" charater and
    /// a colon delimited string where the first parameter is the type
    /// of object to draw and the remaining are the coordinates to draw them.
    /// </summary>
    /// <param name="str"></param>
    override public void FromString(string str)
    {
      string [] drawable = str.Split( new char [] {'/'} );
      foreach(string drawme in drawable)
      {
        string [] draw = drawme.Split( new char[]{':'});
        switch(draw[0])
        {
          case  "h":
            Highlight(ColorTranslator.FromHtml(draw[2]), Convert.ToInt16(draw[3]), draw[1]);
            break;
          case "c":
            Circle(ColorTranslator.FromHtml(draw[2]), Convert.ToInt16(draw[3]), draw[1]);
            break;
          case "x":
            Xmarks(ColorTranslator.FromHtml(draw[2]), Convert.ToInt16(draw[3]), draw[1]);
            break;
          case "a":
            Arrow(ColorTranslator.FromHtml(draw[3]), Convert.ToInt16(draw[4]), draw[1], draw[2]);
            break;
          case "b":            
            //Balloon();
            break;
        }
      }
      IsRedraw = true;
      Parent.IsRedraw = true;
    }

    /// <summary>
    /// When the control is resized, we must ensure that the diagramming decorations
    /// are redrawn as well.
    /// </summary>
    public void Resized()
    {
      string dfen = ToString();
      Clear();
      FromString(dfen);
    }

    /// <summary>
    /// Draws a highlight around the requested square.
    /// </summary>
    /// <param name="color"></param>
    /// <param name="width"></param>
    /// <param name="notation"></param>
    public void Highlight(Color color, int width, string notation)
    {
      ChessSurface cs = (ChessSurface) Parent;
      string name = "h:" +  notation;
      PieceSquare ps = cs.FindPiece(notation);
      if( ps != null)
      {
        if( Color.Transparent == color )
        {
          Remove(name);
        }
        else
        {
          // Always remove as we only want one with this name.
          Remove(name);
          DrawSquare ds = new DrawSquare(cs.Control,color,width);
          ds.Square = ps.Square;
          ds.Name = name;
          Add(ds);
        }
        IsRedraw = true;
        cs.IsRedraw = true;
      }
    }

    /// <summary>
    /// Draws an arrow from the requested coordinate to the requested coordinate.
    /// </summary>
    /// <param name="color"></param>
    /// <param name="width"></param>
    /// <param name="from"></param>
    /// <param name="to"></param>
    public void Arrow(Color color, int width, string from, string to)
    {
      ChessSurface cs = (ChessSurface) Parent;
      PieceSquare psFr = cs.FindPiece(from);
      PieceSquare psTo = cs.FindPiece(to);
      string name = "a:" +  from + ":" + to;
      if( psFr != null && psTo!=null)
      {
        if( Color.Transparent == color )
        {
          Remove(name);
        }
        else
        {
          // Always remove as we only want one with this name.
          Remove(name);
          DrawArrow ds = new DrawArrow(cs.Control,color,width);
          ds.StartPoint = new Point(psFr.Square.X + psFr.Square.Width  / 2,
                                    psFr.Square.Y + psFr.Square.Height / 2);
          ds.EndPoint = new Point(psTo.Square.X + psTo.Square.Width  / 2,
                                  psTo.Square.Y + psTo.Square.Height / 2);
          ds.Name = name;
          Add(ds);
        }
        IsRedraw = true;
        cs.IsRedraw = true;
      }
    }

    /// <summary>
    /// Draws a circle on the requested coordinates of our chess board.
    /// </summary>
    /// <param name="color"></param>
    /// <param name="width"></param>
    /// <param name="notation"></param>
    public void Circle(Color color, int width, string notation)
    {
      ChessSurface cs = (ChessSurface) Parent;
      PieceSquare ps = cs.FindPiece(notation);      
      string name = "c:" + notation;
      if( ps != null)
      {
        if( Color.Transparent == color )
        {
          Remove(name);
        }
        else
        {
          // Always remove as we only want one with this name.
          Remove(name);
          DrawCircle ds = new DrawCircle(cs.Control,color,width);
          ds.Square = ps.Square;
          ds.Name = name;
          Add(ds);
        }
        IsRedraw = true;
        cs.IsRedraw = true;
      }
    }
    /// <summary>
    /// Draws an X on the requested square coordinates of our chess board.
    /// </summary>
    /// <param name="color"></param>
    /// <param name="width"></param>
    /// <param name="notation"></param>
    public void Xmarks(Color color, int width, string notation)
    {
      ChessSurface cs = (ChessSurface) Parent;
      PieceSquare ps = cs.FindPiece(notation);
      string name = "x:" + notation;
      if( ps != null)
      {
        if( Color.Transparent == color )
        {
          Remove(name);
        }
        else
        {
          // Always remove as we only want one with this name.
          Remove(name);
          DrawXmarks ds = new DrawXmarks(cs.Control,color,width);
          ds.Square = ps.Square;
          ds.Name = name;
          Add(ds);
        }
        IsRedraw = true;
        cs.IsRedraw = true;
      }
    }
    /// <summary>
    /// Draws a balloon text box on the chess board control.
    /// </summary>
    /// <param name="text"></param>
    /// <param name="orientation"></param>
    /// <param name="rect"></param>
    public void Balloon(string text, int orientation, Rectangle rect )
    {
      ChessSurface cs = (ChessSurface) Parent;
      string name = "b:" + rect.X + ":" + rect.Y + ":" + rect.Width + ":" + rect.Height;
      if( orientation < 0 )
      {
        Remove(name);
      }
      else
      {
        // Always remove as we only want one with this name.
        Remove(name);
        DrawBalloon ds = new DrawBalloon(cs.Control);
        ds.Settings = coBalloonSettings;
        ds.Orientation = orientation;
        ds.Text = text;
        ds.Square = rect;
        ds.Name = name;
        Add(ds);
      }
      IsRedraw = true;
      cs.IsRedraw = true;
    }
    #region IMouseEvents Members

    public void EnterEvent(object sender, EventArgs e)
    {
    }
    public void LeaveEvent(object sender, EventArgs e)
    {
    }

    public void HoverEvent(object sender, EventArgs e)
    {
    }

    PieceSquare coFirstSquare;
    public void DownEvent(object sender, System.Windows.Forms.MouseEventArgs e)
    {
      ChessSurface cs = (ChessSurface) Parent;
      coFirstSquare = cs.FindPiece(e.X,e.Y);
      if(coFirstSquare!=null)
      {
        switch(coKey)
        {
          case Keys.A:
            break;
          case Keys.C:
            Circle(PenColor,PenWidth,coFirstSquare.Name);
            cs.Control.Invalidate();            
            break;
          case Keys.H:
          case Keys.V:
            Highlight(PenColor,PenWidth,coFirstSquare.Name);
            cs.Control.Invalidate();
            break;
          case Keys.X:
            Xmarks(PenColor,PenWidth,coFirstSquare.Name);
            cs.Control.Invalidate();
            break;
          case Keys.Z:
            Clear();
            cs.Control.Invalidate();
            break;
        }
      }
    }

    public void UpEvent(object sender, System.Windows.Forms.MouseEventArgs e)
    {
      ChessSurface cs = (ChessSurface) Parent;
      PieceSquare ps = cs.FindPiece(e.X,e.Y);
      if( ps!=null && 
          coFirstSquare != null &&
          !ps.Name.Equals(coFirstSquare.Name))
      {
        switch(coKey)
        {
          case Keys.A:
            Arrow(PenColor,PenWidth,coFirstSquare.Name,ps.Name);
            cs.Control.Invalidate();
            break;
          case Keys.C:
            break;
          case Keys.V:
            break;
          case Keys.X:
            break;
        }
      }
    }

    public void MoveEvent(object sender, System.Windows.Forms.MouseEventArgs e)
    {
    }
    #endregion
  }
}
